use std::fmt::{Debug, Display};

pub trait Summary {
    fn summarize(&self) -> String {
        String::from("(Read more...)")
    }
    fn default(&self) -> String {
        String::from("(default...)")
    }
}

pub struct Twitter {
    pub title: String,
    // 标题
    pub author: String, // 作者
}

impl Summary for Twitter {
    fn summarize(&self) -> String {
        format!("文章{}, 作者是{}", self.title, self.author)
    }
}

pub struct QQ {
    pub username: String,
    pub content: String,
}

impl Summary for QQ {
    fn summarize(&self) -> String {
        format!("文章{}, 作者是{}", self.username, self.content)
    }
    fn default(&self) -> String {
        String::from("(QQ default...)")
    }
}

//报错：只能有一个具体的类型 -->特征对象
fn returns_summarizable(switch: bool) -> impl Summary {
    if switch {
        Twitter {
            title: String::from("Penguins win the Stanley Cup Championship!"),
            author: String::from("Iceburgh"),
        }
    } else {
        QQ {
            username: String::from("horse_ebooks"),
            content: String::from("of course, as you probably already know, people"),
        };

        Twitter {
            title: String::from("Penguins win the Stanley Cup Championship!"),
            author: String::from("Iceburgh"),
        }
    }
}

// 类型约束

pub fn some_function_simple(item: &(impl Summary + Display)) {}

pub fn some_function_base<T: Summary + Display>(item: &T) {}

fn some_function<T: Display + Clone, U: Clone + Debug>(t: &T, u: &U) -> i32 {
    1
}

fn some_function_new<T, U>(t: &T, u: &U) -> i32
where
    T: Display + Clone,
    U: Clone + Debug,
{
    1
}

#[cfg(test)]
mod tests {
    use crate::basex::structx::r#trait::{QQ, Summary, Twitter};

    fn say_default(l: impl Summary) -> String {
        return l.summarize();
    }

    pub fn notify<T: Summary>(item: &T) {
        println!("notify! {}", item.summarize());
    }

    // 如果你想要为类型 A 实现特征 T，那么 A 或者 T 至少有一个是在当前作用域中定义的！
    #[test]
    fn base() {
        let twitter = Twitter {
            title: String::from("title"),
            author: String::from("author"),
        };
        let qq = QQ {
            username: String::from("username"),
            content: String::from("content"),
        };
        println!("{}", twitter.summarize());
        println!("{}", twitter.default()); // 默认实现
        println!("{}", qq.default()); // 默认实现
    }

    #[test]
    fn func() {
        let twitter = Twitter {
            title: String::from("title"),
            author: String::from("author"),
        };
        notify(&twitter);
        println!("{}", say_default(twitter));
    }

    #[test]
    fn trans() {
        let a: i32 = 10;
        let b: u16 = 100;
        // try_into -->最常用的标准库中的特征通过 std::prelude 模块提前引入到当前作用域
        let b_ = b.try_into().unwrap();

        if a < b_ {
            println!("Ten is less than one hundred.");
        }
    }
}

mod more_trait {
    use std::fmt::{Debug, Display, Formatter};
    use std::ops::Add;

    #[derive(Debug)]
    struct Pair<T> {
        x: T,
        y: T,
    }

    impl<T> Pair<T> {
        fn new(x: T, y: T) -> Self {
            Self { x, y }
        }
    }

    // 多约束
    impl<T: Display + PartialOrd> Pair<T> {
        fn cmp_display(&self) {
            if self.x >= self.y {
                println!("The largest member is x = {}", self.x);
            } else {
                println!("The largest member is y = {}", self.y);
            }
        }
    }

    //============
    #[derive(Debug)]
    struct Point<T: Add<T, Output = T>> {
        //限制类型T必须实现了Add特征，否则无法进行+操作。
        x: T,
        y: T,
    }

    // 重写Add
    impl<T: Add<T, Output = T>> Add for Point<T> {
        type Output = Point<T>;

        fn add(self, p: Point<T>) -> Point<T> {
            Point {
                x: self.x + p.x,
                y: self.y + p.y,
            }
        }
    }

    fn add<T: Add<T, Output = T>>(a: T, b: T) -> T {
        a + b
    }

    impl<T: Display + Debug> Display for Pair<T> {
        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
            write!(f, "(={}, {}=)", self.x, self.y)
        }
    }

    #[test]
    fn main() {
        let pair = Pair { x: 1, y: 2 };
        println!("{}", pair);
        println!("{:?}", pair); // trait

        let p1 = Point {
            x: 1.1f32,
            y: 1.1f32,
        };
        let p2 = Point {
            x: 2.1f32,
            y: 2.1f32,
        };
        println!("{:?}", add(p1, p2));

        let p3 = Point { x: 1i32, y: 1i32 };
        let p4 = Point { x: 2i32, y: 2i32 };
        println!("{:?}", add(p3, p4));
    }
}
